package com.woniuxy.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

/**
 * 百度OCR工具类：处理token获取和文字识别
 */
@Component
public class BaiduOcrUtils {
    // 从配置文件注入百度API密钥
    @Value("${baidu.ocr.api-key}")
    private String apiKey;
    @Value("${baidu.ocr.secret-key}")
    private String secretKey;
    @Value("${baidu.ocr.token-url}")
    private String tokenUrl;
    @Value("${baidu.ocr.general-url}")
    private String generalUrl;

    // OkHttp客户端（设置超时时间）
    private final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    public void testConnection() throws IOException {
        String token = getAccessToken();
        System.out.println("获取到的Token: " + token);
    }

    /**
     * 获取百度OCR的access_token
     */
    private String getAccessToken() throws IOException {
        String requestUrl = tokenUrl + "?grant_type=client_credentials" +
                "&client_id=" + apiKey +
                "&client_secret=" + secretKey;

        Request request = new Request.Builder().url(requestUrl).get().build();
        Response response = client.newCall(request).execute();

        if (!response.isSuccessful()) {
            throw new IOException("获取百度OCR token失败，状态码: " + response.code());
        }

        String responseBody = response.body().string();
        JSONObject jsonObject = JSONObject.parseObject(responseBody);
        return jsonObject.getString("access_token");
    }

    /**
     * 调用百度OCR通用文字识别接口
     */
    public String recognizeText(byte[] imageBytes) throws IOException {
        // 1. 图片预处理
        byte[] processedImage = preprocessImage(imageBytes);

        // 调试信息
        System.out.println("=== 图片信息调试 ===");
        System.out.println("原始大小: " + imageBytes.length + " bytes");
        System.out.println("处理后大小: " + processedImage.length + " bytes");
        System.out.println("文件头: " + bytesToHex(processedImage, 8));

        // 2. 转换为Base64
        String base64Image = Base64.getEncoder().encodeToString(processedImage);

        // 3. 构建请求参数
        String params = "image=" + URLEncoder.encode(base64Image, "UTF-8") +
                "&image_type=BASE64" +
                "&language_type=CHN_ENG" +
                "&detect_direction=false" +
                "&detect_language=false";

        // 4. 构建POST请求
        Request request = new Request.Builder()
                .url(generalUrl + "?access_token=" + getAccessToken())
                .post(RequestBody.create(
                        MediaType.parse("application/x-www-form-urlencoded"),
                        params
                ))
                .build();

        // 5. 发送请求并解析结果
        Response response = client.newCall(request).execute();
        String responseBody = response.body().string();
        JSONObject resultJson = JSONObject.parseObject(responseBody);

        // 6. 错误处理
        if (resultJson.containsKey("error_code")) {
            String errorMsg = resultJson.getString("error_msg");
            throw new IOException("百度OCR识别失败: " + errorMsg +
                    "（错误码: " + resultJson.getString("error_code") + "）");
        }

        // 7. 提取识别结果
        StringBuilder textResult = new StringBuilder();
        JSONArray wordsArray = resultJson.getJSONArray("words_result");
        for (int i = 0; i < wordsArray.size(); i++) {
            textResult.append(wordsArray.getJSONObject(i).getString("words")).append("\n");
        }

        return textResult.toString().trim();
    }

    /**
     * 图片预处理方法
     */
    private byte[] preprocessImage(byte[] original) throws IOException {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(original);
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            BufferedImage image = ImageIO.read(bais);
            if (image == null) {
                throw new IOException("无法识别的图片格式");
            }

            // 统一转换为RGB格式（去除Alpha通道）
            BufferedImage convertedImage = new BufferedImage(
                    image.getWidth(),
                    image.getHeight(),
                    BufferedImage.TYPE_INT_RGB);

            // 绘制到新图像（白色背景）
            Graphics2D g = convertedImage.createGraphics();
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, image.getWidth(), image.getHeight());
            g.drawImage(image, 0, 0, null);
            g.dispose();

            // 根据原始格式选择输出格式
            String formatName = "jpg"; // 默认JPEG
            if (isPng(original)) {
                formatName = "png";
            } else if (isBmp(original)) {
                formatName = "bmp";
            }

            // 写入输出流
            if (!ImageIO.write(convertedImage, formatName, baos)) {
                throw new IOException("无法生成" + formatName + "格式图片");
            }

            return baos.toByteArray();
        }
    }

    private boolean isPng(byte[] data) {
        return data.length >= 8 &&
                data[0] == (byte) 0x89 &&
                new String(data, 1, 3).equals("PNG");
    }

    private boolean isJpeg(byte[] data) {
        return data.length >= 2 &&
                data[0] == (byte) 0xFF &&
                data[1] == (byte) 0xD8;
    }

    private boolean isBmp(byte[] data) {
        return data.length >= 2 &&
                new String(data, 0, 2).equals("BM");
    }

    /**
     * 字节数组转十六进制字符串（调试用）
     */
    private String bytesToHex(byte[] bytes, int length) {
        if (bytes == null || bytes.length == 0) {
            return "empty";
        }

        StringBuilder sb = new StringBuilder();
        int maxLength = Math.min(bytes.length, length);

        for (int i = 0; i < maxLength; i++) {
            sb.append(String.format("%02X ", bytes[i] & 0xFF));
            if ((i + 1) % 4 == 0) sb.append("| ");
        }

        if (bytes.length < length) {
            sb.append("(only ").append(bytes.length).append(" bytes)");
        }

        return sb.toString().trim();
    }
}